package cate.game.activity.skindraw;

import cate.common.annotation.SplitParse;
import cate.common.table.activity.skindraw.row.SkinDrawBaseRow;
import cate.common.table.activity.skindraw.row.SkinDrawPoolRow;
import cate.common.table.activity.skindraw.row.SkinDrawRewardRow;
import cate.common.table.d.GDOperation;
import cate.common.table.item.ItemBaseRow;
import cate.common.util.GameResult;
import cate.common.util.SplitParser;
import cate.game.activity.base.core.RoleActivitySingle;
import cate.game.activity.skindraw.msg.DrawSkinResp;
import cate.game.activity.skindraw.msg.SkinDrawInfoResp;
import cate.game.chat.ChatContentParam;
import cate.game.res.MixRes;
import cate.game.res.MixResAdder;
import cate.game.res.MixResItem;
import cate.game.role.Role;
import com.fasterxml.jackson.annotation.JsonIgnore;
import cp.solution.business.game.component.NoticeParam;
import easy.java.dev.note.NoteClass;
import easy.java.dev.note.NoteField;
import easy.java.practice.errorcode.EcResult;
import org.apache.commons.lang3.StringUtils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@NoteClass("皮肤抽奖活动")
public class SkinDrawActivity extends RoleActivitySingle {
    @NoteField("选中的皮肤id")
    public int selectedId;
    @NoteField("累计抽奖次数")
    public int historyDrawTimes;
    @JsonIgnore
    @NoteField("防脸白")
    public int minDrawTimes;
    @NoteField("保底抽奖次数")
    public int drawTimes;
    @NoteField("剩余免费次数")
    public int freeTimes;
    @NoteField("钻石召唤次数")
    public int diaTimes;
    @NoteField("已充值金额(分)")
    public int payNum;
    @NoteField("次数奖励领取记录")
    public Map<Integer, Boolean> numRewardMap;
    @JsonIgnore
    @NoteField("保底权重")
    Map<Integer,Double> cheatWeight;

    @NoteField("已抽皮肤")
    Map<Integer,Double> cheatIds;

    @Override
    public void initialize(Role role) {
        super.initialize(role);
        if (numRewardMap == null) {
            numRewardMap = new HashMap<>();
        }
        if (cheatWeight == null) {
            cheatWeight = new HashMap<>();
        }
        if (cheatIds == null) {
            cheatIds = new HashMap<>();
        }
        role.getActivity().registerRecharge(this, this::onPay);
    }

    /**
     * 人民币增加
     * @param pay
     */
    public void onPay(long pay) {
        if (!enable()) {
            return;
        }
        payNum += pay;
        noticeUpdate();
    }

    public void clear() {
        payNum = 0;
        freeTimes = 0;
        selectedId = 0;
        drawTimes = 0;
        diaTimes = 0;
        historyDrawTimes = 0;
        minDrawTimes = 0;
        numRewardMap.clear();
        cheatWeight.clear();
        cheatIds.clear();
    }

    @Override
    public void onRoleOpen() {
    }

    @Override
    public void onRoleEnd() {
        clear();
    }

    @Override
    public void initSend() {
        noticeUpdate();
    }

    @Override
    public void excelCheck() {
        SkinDrawBaseRow baseRow = showBaseRow();
        if (baseRow == null) {
            return ;
        }
        numRewardMap.entrySet().removeIf(entry -> role.getGame().table.skinDraw.reward.get(entry.getKey()) == null);
        for (SkinDrawRewardRow row : role.getGame().table.skinDraw.reward.getList()) {
            if (!numRewardMap.containsKey(row.id) && row.group == baseRow.timesGroup) {
                numRewardMap.put(row.id, false);
            }
        }
        if (selectedId == 0) {
            this.freeTimes = baseRow.limit;
            List<Integer> ids = baseRow.pickSellParams.stream().map(param -> param.sellTid).collect(Collectors.toList());
            this.selectedId = ids.get(0);
        }
        getCheatWeights(baseRow);
    }

    private void getCheatWeights(SkinDrawBaseRow baseRow) {
        if (StringUtils.isNotBlank(baseRow.cheatStr)) {
            cheatWeight = new HashMap<>();
            List<CheatParam> cheatParams = SplitParser.parse(CheatParam.class, baseRow.cheatStr);
            for (CheatParam param : cheatParams) {
                cheatWeight.put(param.cheatId, param.weight);
            }
        }
    }

    @NoteClass(value = "保底权重配置")
    public static final class CheatParam {
        @SplitParse(order = 0)
        public int cheatId;

        @SplitParse(order = 1, defaultValue = "0")
        public double weight;
    }



    private SkinDrawBaseRow showBaseRow() {
        return role.getGame().table.skinDraw.base.get(configTid());
    }

    @Override
    public void onDaySpan(boolean silence) {
        super.onDaySpan(silence);
        if (!enable()) {
            return;
        }
        SkinDrawBaseRow baseRow = showBaseRow();
        if (baseRow == null) {
            return;
        }
        this.freeTimes = baseRow.limit;
        this.diaTimes = 0;
        noticeUpdate();
    }

    /**
     * 选定英雄皮肤
     * @param skinId
     * @return
     */
    public GameResult<SkinDrawActivity> chooseSkin(int skinId) {
        GameResult<SkinDrawActivity> r = new GameResult<>();
        SkinDrawBaseRow baseRow = showBaseRow();
        if (baseRow == null) {
            return r.fail("活动配置不存在");
        }
        List<Integer> ids = baseRow.pickSellParams.stream().map(param -> param.sellTid).collect(Collectors.toList());
        if (!ids.contains(skinId)) {
            return r.fail("选择了不存在的物品");
        }
        this.selectedId = skinId;
        noticeUpdate();
        return r;
    }

    public void noticeUpdate() {
        role.sendNow(new SkinDrawInfoResp(this));
    }

    /**
     * 单抽
     * @return
     */
    public GameResult<SkinDrawActivity> singleDraw() {
        GameResult<SkinDrawActivity> r = new GameResult<>();
        SkinDrawBaseRow baseRow = showBaseRow();
        boolean isDia = false;
        MixRes cost = new MixRes(baseRow.oneCost);
        if (baseRow == null) {
            return r.fail("活动配置不存在");
        }
        boolean isFree = false;
        //免费抽
        if (freeTimes > 0) {
            freeTimes --;
            isFree = true;
        } else {
            if (StringUtils.isBlank(baseRow.oneCost)) {
                return r.fail("消耗未配置");
            }
            //道具消耗
            GameResult<MixResItem> consume = cost.consumeCheck(role);
            /*if (!consume.ok()) {
                if (diaTimes >= baseRow.diaTimes) {
                    return r.fail("钻石抽奖次数已达上限");
                }
                //钻石消耗
                cost = new MixRes(baseRow.diaCost);
                GameResult<MixResItem> consumeDia = cost.consumeCheck(role);
                if (!consumeDia.ok()) {
                    return r.fail(consumeDia);
                }
                isDia = true;
                diaTimes ++;
            }*/

            if (!consume.ok()) {
                return r.fail(consume);
            }
        }
        r = draw(1, isDia);
        if (r.ok()  && !isFree) {
            cost.consume(role);
        }
        return r;
    }

    /**
     * 十连
     * @return
     */
    public GameResult<SkinDrawActivity> tenDraw() {
        GameResult<SkinDrawActivity> r = new GameResult<>();
        SkinDrawBaseRow baseRow = showBaseRow();
        if (baseRow == null) {
            return r.fail("活动配置不存在");
        }
        if (StringUtils.isBlank(baseRow.tenCost)) {
            return r.fail("消耗未配置");
        }
        boolean isDia = false;
        //道具消耗
        MixRes cost = new MixRes(baseRow.tenCost);
        GameResult<MixResItem> consume = cost.consumeCheck(role);
        /*if (!consume.ok()) {
            if (diaTimes >= baseRow.diaTimes || ((diaTimes + 10) > baseRow.diaTimes )) {
                return r.fail("钻石抽奖次数已达上限");
            }
            //钻石消耗
            cost = new MixRes(baseRow.diaCost);
            cost.multiply(10);
            GameResult<MixResItem> consumeDia = cost.consumeCheck(role);
            if (!consumeDia.ok()) {
                return r.fail(consumeDia);
            }
            isDia = true;
            diaTimes += 10;
        }*/
        if (!consume.ok()) {
            return r.fail(consume);
        }
        r = draw(10, isDia);
        if (r.ok()) {
            cost.consume(role);
        }
        return r;
    }

    /**
     * 随机抽奖
     * @param times
     * @return
     */
    private GameResult<SkinDrawActivity> draw(int times, boolean isDia) {
        GameResult<SkinDrawActivity> r = new GameResult<>();
        SkinDrawBaseRow baseRow = showBaseRow();
        MixRes rewards = new MixRes();
        List<MixRes> rewardShow = new ArrayList<>();
        int rareNum = 0;
        List<SkinDrawPoolRow> rows = new ArrayList<>();
        long startMs = System.currentTimeMillis();
        while (rows.size() < times) {
            if (System.currentTimeMillis() - startMs > 5000L) {
                break;
            }
            SkinDrawPoolRow row = role.getGame().table.skinDraw.drawPool.randomPool(baseRow.normalGroup,0,0, cheatIds);
            if (drawTimes >= (baseRow.cheatTime - 1)) {
                //保底
                row = role.getGame().table.skinDraw.drawPool.randomPool(baseRow.cheatGroup,0,0, cheatIds);
            } else if (payNum >= (baseRow.recharge * 100) && minDrawTimes >= baseRow.minTimes) {
                //充值，次数
                row = role.getGame().table.skinDraw.drawPool.randomPool(baseRow.rechargeGroup, selectedId, baseRow.getParam(this.selectedId).weight, cheatIds);
            }
            if (row.rare && rareNum < baseRow.rare) {
                rareNum ++;
                drawTimes = 0;
                minDrawTimes ++;
                historyDrawTimes ++;
                rows.add(row);
                changeRow(row);
                if (baseRow.lampId != 0) {
                    List<ChatContentParam> params = new ArrayList<>();
                    params.add(ChatContentParam.c(role.getBase().name));
                    params.add(ChatContentParam.c(ChatContentParam.TYPE_MIX_RES, new MixRes(row.reward)));
                    role.getGame().notice.lampOnline(role, baseRow.lampId, params);
                }
                rewards.addList(new MixRes(row.reward));
                rewardShow.add(new MixRes(row.reward));
            } else if (!row.rare) {
                drawTimes ++ ;
                if (drawTimes >= baseRow.cheatTime) {
                    //保底
                    drawTimes = 0;
                }
                minDrawTimes ++;
                historyDrawTimes ++;
                rows.add(row);
                rewards.addList(new MixRes(row.reward));
                rewardShow.add(new MixRes(row.reward));
            }
            if (cheatWeight.containsKey(row.skinId)) {
                drawTimes = 0;
            }
        }
        //钻石抽奖赠送经验
        if (isDia) {
            MixRes expRwd = new MixRes(baseRow.exp).multiply(times);
            rewards.addList(expRwd);
        }
        EcResult<?> exe = new MixResAdder().setRes(rewards)
                .setOperation(GDOperation.SKIN_DRAW)
                .setDialogReward(false)
                .setSendMailWhenFull(true)
                .exe(role);

        DrawSkinResp resp = new DrawSkinResp(rewardShow);
        resp.sendNow(role);
        noticeUpdate();
        return r;
    }

    public void changeRow(SkinDrawPoolRow rowRandom){
        //保底权重设置
        if (cheatWeight.containsKey(rowRandom.skinId)) {
            cheatIds.put(rowRandom.skinId, rowRandom.weight);
        }

        //保底权重重置
        if (cheatWeight.size() == cheatIds.size()) {
            cheatIds = new HashMap<>();
        }
    }

    /**
     * 领取次数奖励
     * @param tid
     * @return
     */
    public GameResult<SkinDrawActivity> takeTimesReward(int tid) {
        GameResult<SkinDrawActivity> r = new GameResult<>();
        SkinDrawBaseRow baseRow = showBaseRow();
        if (baseRow == null) {
            return r.fail("活动配置不存在");
        }
        SkinDrawRewardRow row = showDrawRewardRow(tid);
        if (row == null || !numRewardMap.containsKey(tid)) {
            return r.fail("奖励配置不存在");
        }
        if (numRewardMap.get(tid)) {
            return r.fail("奖励已领取");
        }
        if (historyDrawTimes < row.times) {
            return r.fail("抽奖次数不足");
        }
        MixRes res = new MixRes(row.rewardStr);
        EcResult<?> exe = new MixResAdder().setRes(res)
                .setOperation(GDOperation.LOTTERY)
                .setDialogReward(true)
                .setSendMailWhenFull(true)
                .exe(role);
        numRewardMap.put(tid, true);
        checkMapStatus();
        noticeUpdate();
        return r;
    }

    /**
     * 累计次数重置检查
     */
    private void checkMapStatus() {
        boolean check = true;
        if (numRewardMap.containsValue(false)){
            check = false;
        }
        if (check) {
            SkinDrawBaseRow baseRow = showBaseRow();
            if (baseRow == null) {
                return;
            }
            numRewardMap = new HashMap<>();
            int maxScore = 0;
            for (SkinDrawRewardRow row : role.getGame().table.skinDraw.reward.getList()) {
                if (row.group == baseRow.timesGroup) {
                    numRewardMap.put(row.id, false);
                    maxScore = Math.max(maxScore, row.times);
                }
            }
            historyDrawTimes -= maxScore;
        }
    }

    private SkinDrawRewardRow showDrawRewardRow(int tid) {
        return role.getGame().table.skinDraw.reward.get(tid);
    }

}
